﻿using System.Collections;
using System.Collections.Generic;
using MugenInjection.Interface;

namespace MugenInjection.Infrastructure
{
    /// <summary>
    ///    The class to represent <see cref="ISettings" /> as Dictionary.
    /// </summary>
    public sealed class DictionarySettingsImpl : ISettings
    {
        #region Fields

        private readonly IDictionary<string, object> _settingsDictionary;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="DictionarySettingsImpl"/> class.
        /// </summary>
        public DictionarySettingsImpl()
            : this(new Dictionary<string, object>())
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DictionarySettingsImpl"/> class.
        /// </summary>
        public DictionarySettingsImpl(IDictionary<string, object> dictionary)
        {
            Validate.ArgumentNotNull(dictionary, "dictionary");
            _settingsDictionary = dictionary;
        }

        #endregion

        #region Implementation of ISettings

        /// <summary>
        ///     Gets or sets the value associated with specified name.
        /// </summary>
        /// <param name="name">The setting name of the value to get or set.</param>
        /// <returns>The specified setting value.</returns>
        public object this[string name]
        {
            get
            {
                lock (_settingsDictionary)
                    return _settingsDictionary[name];
            }
            set
            {
                lock (_settingsDictionary)
                    _settingsDictionary[name] = value;
            }
        }

        /// <summary>
        ///     Adds the value associated with specified name.
        /// </summary>
        /// <param name="name">The setting name of the value to set.</param>
        /// <param name="obj">The specified setting value.</param>
        public void Add(string name, object obj)
        {
            Validate.ArgumentNotNull(name, "name");
            lock (_settingsDictionary)
                _settingsDictionary.Add(name, obj);
        }

        /// <summary>
        ///     Removes the value associated with specified name.
        /// </summary>
        /// <param name="name">The setting name of the value to remove.</param>
        public bool Remove(string name)
        {
            Validate.ArgumentNotNull(name, "name");
            lock (_settingsDictionary)
                return _settingsDictionary.Remove(name);
        }

        /// <summary>
        ///     Gets the value associated with specified name.
        /// </summary>
        /// <param name="name">The setting name of the value to get.</param>
        /// <returns>The specified setting value.</returns>
        public object Get(string name)
        {
            Validate.ArgumentNotNull(name, "name");
            return this[name];
        }


        /// <summary>
        ///     Gets the value associated with specified name.
        /// </summary>
        /// <param name="name">The setting name of the value to get.</param>
        /// <returns>The specified setting value.</returns>
        public T Get<T>(string name)
        {
            return (T)Get(name);
        }

        /// <summary>
        ///     Try gets the value associated with specified name.
        /// </summary>
        /// <param name="name">The setting name of the value to get.</param>
        /// <param name="result">The specified setting value.</param>
        /// <returns>
        ///     <c>True</c> if the specified setting has been resolved; otherwise, <c>false</c>.
        /// </returns>
        public bool TryGet(string name, out object result)
        {
            Validate.ArgumentNotNull(name, "name");
            lock (_settingsDictionary)
                return _settingsDictionary.TryGetValue(name, out result);
        }

        /// <summary>
        ///     Try gets the value associated with specified name.
        /// </summary>
        /// <param name="name">The setting name of the value to get.</param>
        /// <param name="result">The specified setting value.</param>
        /// <returns>
        ///     <c>True</c> if the specified setting has been resolved; otherwise, <c>false</c>.
        /// </returns>
        public bool TryGet<T>(string name, out T result)
        {
            object obj;
            bool tryGet = TryGet(name, out obj);
            result = tryGet ? (T)obj : default(T);
            return tryGet;
        }

        /// <summary>
        ///     Determines whether the specified setting name can be resolved.
        /// </summary>
        /// <param name="name">The setting name of the value to check.</param>
        /// <returns>
        ///     <c>True</c> if the specified setting has been contains; otherwise, <c>false</c>.
        /// </returns>
        public bool IsContain(string name)
        {
            Validate.ArgumentNotNull(name, "name");
            lock (_settingsDictionary)
                return _settingsDictionary.ContainsKey(name);
        }

        /// <summary>
        ///     Removes all settings.
        /// </summary>
        public void Clear()
        {
            lock (_settingsDictionary)
                _settingsDictionary.Clear();
        }

        /// <summary>
        /// Converts settings to dictionary.
        /// </summary>
        /// <returns>An instance of <see cref="IDictionary{TKey,TValue}"/></returns>
        public IDictionary<string, object> ToDictionary()
        {
            return _settingsDictionary;
        }

        #endregion

        #region Implementation of IEnumerable

        /// <summary>
        ///     Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        ///     A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
        /// </returns>
        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
        {
            return _settingsDictionary.GetEnumerator();
        }

        /// <summary>
        ///     Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        ///     An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }
}